﻿using PmSoft.Core.Extensions;

namespace PmSoft.Core.FileStorage.Providers;

/// <summary>
/// 本地文件系统存储提供商，实现了 IFileStorageProvider 接口
/// </summary>
public class LocalFileSystemStorageProvider : IFileStorageProvider
{
	private readonly string _rootPath;

	/// <summary>
	/// 构造函数，初始化本地文件系统的根路径
	/// </summary>
	/// <param name="rootPath">文件存储的根目录，例如 "/var/storage"</param>
	public LocalFileSystemStorageProvider(string rootPath)
	{
		// 如果 rootPath 为空或 null，则使用当前工作目录
		_rootPath = string.IsNullOrWhiteSpace(rootPath) ? Path.Combine(Environment.CurrentDirectory, "FileStorage") : rootPath;
	}

	/// <summary>
	/// 异步保存文件到本地文件系统
	/// </summary>
	/// <param name="args">保存文件参数</param>
	/// <returns>表示异步操作的任务</returns>
	public async Task SaveFileAsync(SaveFileArgs args)
	{
		var normalizedPath = NormalizePath(args.Path);
		var directoryPath = Path.Combine(_rootPath, args.BucketName, normalizedPath); // 组合目录路径
		if (!Directory.Exists(directoryPath))
			Directory.CreateDirectory(directoryPath); // 确保目录存在
		var filePath = Path.Combine(directoryPath, args.ObjectName); // 组合完整文件路径
		await File.WriteAllBytesAsync(filePath, args.Data); // 写入文件
	}

	/// <summary>
	/// 同步保存文件到本地文件系统
	/// </summary>
	/// <param name="args">保存文件参数</param>
	public void SaveFile(SaveFileArgs args)
	{
		SaveFileAsync(args).GetAwaiter().GetResult(); // 调用异步方法并等待结果
	}

	/// <summary>
	/// 异步从本地文件系统删除文件
	/// </summary>
	/// <param name="args">删除文件参数</param>
	/// <returns>表示异步操作的任务</returns>
	public async Task DeleteFileAsync(DeleteFileArgs args)
	{
		var normalizedPath = NormalizePath(args.Path);
		var filePath = Path.Combine(_rootPath, args.BucketName, normalizedPath, args.ObjectName); // 组合文件路径
		if (File.Exists(filePath))
		{
			await Task.Run(() => File.Delete(filePath)); // 删除文件
		}
	}

	/// <summary>
	/// 同步从本地文件系统删除文件
	/// </summary>
	/// <param name="args">删除文件参数</param>
	public void DeleteFile(DeleteFileArgs args)
	{
		DeleteFileAsync(args).GetAwaiter().GetResult(); // 调用异步方法并等待结果
	}

	/// <summary>
	/// 异步判断文件在本地文件系统中是否存在
	/// </summary>
	/// <param name="args">判断文件是否存在参数</paraqm>
	/// <returns>布尔值，表示文件是否存在</returns>
	public async Task<bool> FileExistsAsync(FileExistsArgs args)
	{
		var normalizedPath = NormalizePath(args.Path);
		var filePath = Path.Combine(_rootPath, args.BucketName, normalizedPath, args.ObjectName); // 组合文件路径
		return await Task.FromResult(File.Exists(filePath)); // 检查文件是否存在
	}

	/// <summary>
	/// 同步判断文件在本地文件系统中是否存在
	/// </summary>
	/// <param name="args">判断文件是否存在参数</param>
	/// <returns>布尔值，表示文件是否存在</returns>
	public bool FileExists(FileExistsArgs args)
	{
		return FileExistsAsync(args).GetAwaiter().GetResult(); // 调用异步方法并等待结果
	}

	/// <summary>
	/// 异步从本地文件系统获取文件
	/// </summary>
	/// <param name="args">获取文件参数</param>
	/// <returns>文件数据对象，如果文件不存在则返回 null</returns>
	public async Task<FileData?> GetFileAsync(GetFileArgs args)
	{
		var normalizedPath = NormalizePath(args.Path);
		var filePath = Path.Combine(_rootPath, args.BucketName, normalizedPath, args.ObjectName); // 组合文件路径
		if (File.Exists(filePath))
		{
			var data = await File.ReadAllBytesAsync(filePath); // 读取文件内容
			return new FileData { Data = data }; // 返回文件数据
		}
		return null; // 文件不存在
	}

	/// <summary>
	/// 同步从本地文件系统获取文件
	/// </summary>
	/// <param name="args">获取文件参数</param>
	/// <returns>文件数据对象，如果文件不存在则返回 null</returns>
	public FileData? GetFile(GetFileArgs args)
	{
		return GetFileAsync(args).GetAwaiter().GetResult(); // 调用异步方法并等待结果
	}

	/// <summary>
	/// 异步移动本地文件系统中的文件
	/// </summary>
	/// <param name="args">移动文件参数</param>
	/// <returns>表示异步操作的任务</returns>
	public async Task MoveFileAsync(MoveFileArgs args)
	{
		try
		{
			var normalizedSourceObjectName = NormalizePath(args.SourceObjectName);
			var normalizedDestObjectName = NormalizePath(args.DestObjectName);
			var sourcePath = Path.Combine(_rootPath, args.SourceBucketName, normalizedSourceObjectName);
			var destPath = Path.Combine(_rootPath, args.DestBucketName, normalizedDestObjectName);

			if (!File.Exists(sourcePath))
				throw new FileNotFoundException("源文件不存在。");

			var destDirectory = Path.GetDirectoryName(destPath);
			if (string.IsNullOrEmpty(destDirectory))
				throw new InvalidOperationException("目标文件路径无效。");
			if (!Directory.Exists(destDirectory))
				Directory.CreateDirectory(destDirectory);

			await Task.Run(() => File.Move(sourcePath, destPath)).ConfigureAwait(false);
		}
		catch (Exception ex)
		{
			throw new InvalidOperationException($"移动本地文件失败: {ex.Message}", ex);
		}
	}

	/// <summary>
	/// 同步移动本地文件系统中的文件
	/// </summary>
	/// <param name="args">移动文件参数</param>
	public void MoveFile(MoveFileArgs args)
	{
		MoveFileAsync(args).GetAwaiter().GetResult();
	}

	// <summary>
	/// 将路径中的 "/" 转换为平台特定的分隔符
	/// </summary>
	/// <param name="path">原始路径，可能包含 "/"</param>
	/// <returns>规范化后的路径</returns>
	private string NormalizePath(string? path)
	{
		if (string.IsNullOrEmpty(path))
			return string.Empty;
		// 将 "/" 替换为当前平台的路径分隔符（Windows 为 "\", Linux 为 "/"）
		return path.Replace("/", Path.DirectorySeparatorChar.ToString());
	}
}